---
title: Mint Tokens
description:
  Learn how to mint tokens in Solana programs using Anchor. Covers creating new
  tokens via cross program invocations (CPI) to the Token Program with code
  examples.
---

## How to Mint Tokens

Minting tokens refers to the process of creating new units of a token by
invoking the
[`mint_to`](https://github.com/solana-program/token/blob/main/program/src/instruction.rs#L1087-L1114)
instruction on a token program. Only the address specified as the mint authority
on the mint account can mint new tokens. The instruction also requires the
existence of a token account for the mint as the destination of the minted
tokens.

<Callout type="info">
  The [Token
  Program](https://github.com/solana-program/token/blob/main/program/src/processor.rs#L523-L585)
  and [Token Extension
  Program](https://github.com/solana-program/token-2022/blob/main/program/src/processor.rs#L962-L1048)
  share similar implementations to achieve the same functionality.
</Callout>

## Examples

To mint tokens through an Anchor program, you need to make a cross program
invocation (CPI) to the `mint_to` instruction on either the Token Program or
Token Extension Program.

This means you are invoking the `mint_to` instruction on the Token Program or
Token Extension Program from an instruction in your program. Your program acts
as an intermediary, passing along the required accounts, instruction data, and
signatures to the token program.

### Mint Tokens via CPI

Use the `token_interface::mint_to` function make a CPI to either the Token
Program or Token Extension Program. This function requires:

1. The `MintTo` struct which specifies the required accounts:

   - `mint` - The mint account to create new units of tokens for
   - `to` - The destination token account to receive the minted tokens
   - `authority` - The mint authority with permission to mint tokens

2. The `amount` of tokens to mint, in base units of the token adjusted by
   decimals. (e.g. if the mint has 2 decimals, amount of 100 = 1 token)

The mint authority passed to the `mint_to` instruction must match the
`mint_authority` stored on the mint account. Additionally, the mint authority
must be a signer on the transaction. For example:

```rust title="lib.rs"
use anchor_lang::prelude::*;
use anchor_spl::{
    token_interface::{self, Mint, MintTo, TokenAccount, TokenInterface},
};

declare_id!("3pX5NKLru1UBDVckynWQxsgnJeUN3N1viy36Gk9TSn8d");

#[program]
pub mod token_example {
    use super::*;

    pub fn mint_tokens(ctx: Context<MintTokens>, amount: u64) -> Result<()> {
        let cpi_accounts = MintTo {
            mint: ctx.accounts.mint.to_account_info(),
            to: ctx.accounts.token_account.to_account_info(),
            authority: ctx.accounts.signer.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
        token_interface::mint_to(cpi_context, amount)?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct MintTokens<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(mut)]
    pub mint: InterfaceAccount<'info, Mint>,
    #[account(mut)]
    pub token_account: InterfaceAccount<'info, TokenAccount>,
    pub token_program: Interface<'info, TokenInterface>,
}
```

At minimum, the following accounts are required:

```rust title="snippet"
#[derive(Accounts)]
pub struct MintTokens<'info> {
    // The mint authority
    #[account(mut)]
    pub signer: Signer<'info>,
    // The mint account
    #[account(mut)]
    pub mint: InterfaceAccount<'info, Mint>,
    // The destination token account
    #[account(mut)]
    pub token_account: InterfaceAccount<'info, TokenAccount>,
    // The token program
    pub token_program: Interface<'info, TokenInterface>,
}
```

Within the instruction logic, use the:

- `MintTo` struct to specify the required accounts
- `token_interface::mint_to` function to make the CPI

```rust title="snippet"
pub fn mint_tokens(ctx: Context<MintTokens>, amount: u64) -> Result<()> {
    // Create the MintTo struct with the accounts required for the CPI
    let cpi_accounts = MintTo {
        mint: ctx.accounts.mint.to_account_info(),
        to: ctx.accounts.token_account.to_account_info(),
        authority: ctx.accounts.signer.to_account_info(),
    };

    // The program being invoked in the CPI
    let cpi_program = ctx.accounts.token_program.to_account_info();

    // Combine the accounts and program into a "CpiContext"
    let cpi_context = CpiContext::new(cpi_program, cpi_accounts);

    // Make CPI to mint_to instruction on the token program
    token_interface::mint_to(cpi_context, amount)?;
    Ok(())
}
```

### Mint Tokens with PDA mint authority via CPI

You can create a mint account with a Program Derived Address (PDA) as the mint
authority. This allows your program to programmatically mint tokens by "signing"
with the PDA's seeds in the Cross Program Invocation (CPI). This pattern is
useful when you want the program itself, rather than an external wallet, to
control token minting.

<Tabs items={["Program", "Client"]}>
<Tab value="Program">

```rust title="lib.rs"
use anchor_lang::prelude::*;
use anchor_spl::{
    associated_token::AssociatedToken,
    token_interface::{self, Mint, MintTo, TokenAccount, TokenInterface},
};

declare_id!("3pX5NKLru1UBDVckynWQxsgnJeUN3N1viy36Gk9TSn8d");

#[program]
pub mod token_example {
    use super::*;

    pub fn create_mint(ctx: Context<CreateMint>) -> Result<()> {
        msg!("Created Mint Account: {:?}", ctx.accounts.mint.key());
        Ok(())
    }

    pub fn mint_tokens(ctx: Context<MintTokens>, amount: u64) -> Result<()> {
        let signer_seeds: &[&[&[u8]]] = &[&[b"mint", &[ctx.bumps.mint]]];

        let cpi_accounts = MintTo {
            mint: ctx.accounts.mint.to_account_info(),
            to: ctx.accounts.token_account.to_account_info(),
            authority: ctx.accounts.mint.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_context = CpiContext::new(cpi_program, cpi_accounts).with_signer(signer_seeds);
        // [!code highlight]
        token_interface::mint_to(cpi_context, amount)?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        init,
        payer = signer,
        mint::decimals = 6,
        mint::authority = mint,
        mint::freeze_authority = mint,
        seeds = [b"mint"],
        bump
    )]
    pub mint: InterfaceAccount<'info, Mint>,
    pub token_program: Interface<'info, TokenInterface>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct MintTokens<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        init_if_needed,
        payer = signer,
        associated_token::mint = mint,
        associated_token::authority = signer,
        associated_token::token_program = token_program,
    )]
    pub token_account: InterfaceAccount<'info, TokenAccount>,
    #[account(
        mut,
        seeds = [b"mint"],
        bump
    )]
    pub mint: InterfaceAccount<'info, Mint>,
    pub token_program: Interface<'info, TokenInterface>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub system_program: Program<'info, System>,
}
```

</Tab>
<Tab value="Client">

```ts title="test.ts"
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { TokenExample } from "../target/types/token_example";
import {
  TOKEN_2022_PROGRAM_ID,
  getAssociatedTokenAddress,
  getMint,
  getAccount,
} from "@solana/spl-token";

describe("token-example", () => {
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.TokenExample as Program<TokenExample>;
  const [mint, mintBump] = anchor.web3.PublicKey.findProgramAddressSync(
    [Buffer.from("mint")],
    program.programId,
  );

  const [token, tokenBump] = anchor.web3.PublicKey.findProgramAddressSync(
    [Buffer.from("token")],
    program.programId,
  );

  it("Is initialized!", async () => {
    const tx = await program.methods
      .createMint()
      .accounts({
        tokenProgram: TOKEN_2022_PROGRAM_ID,
      })
      .rpc({ commitment: "confirmed" });
    console.log("Your transaction signature", tx);

    const mintAccount = await getMint(
      program.provider.connection,
      mint,
      "confirmed",
      TOKEN_2022_PROGRAM_ID,
    );

    console.log("Mint Account", mintAccount);
  });

  it("Mint Tokens", async () => {
    const tx = await program.methods
      .mintTokens(new anchor.BN(100))
      .accounts({
        tokenProgram: TOKEN_2022_PROGRAM_ID,
      })
      .rpc({ commitment: "confirmed" });

    console.log("Your transaction signature", tx);

    const associatedTokenAccount = await getAssociatedTokenAddress(
      mint,
      program.provider.publicKey,
      false,
      TOKEN_2022_PROGRAM_ID,
    );

    const tokenAccount = await getAccount(
      program.provider.connection,
      associatedTokenAccount,
      "confirmed",
      TOKEN_2022_PROGRAM_ID,
    );

    console.log("Token Account", tokenAccount);
  });
});
```

</Tab>
</Tabs>

In this example, mint authority is set to a Program Derived Address (PDA). The
PDA is derived using the seed `b"mint"`. This means the program itself controls
minting through this PDA.

```rust title="snippet"
#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        init,
        payer = signer,
        mint::decimals = 6,
        // [!code word: mint,]
        // [!code highlight]
        mint::authority = mint,
        mint::freeze_authority = mint,
        seeds = [b"mint"],
        bump
    )]
    // [!code word:mint]
    pub mint: InterfaceAccount<'info, Mint>,
    pub token_program: Interface<'info, TokenInterface>,
    pub system_program: Program<'info, System>,
}
```

To mint tokens, the program must "sign" with the PDA by including the seeds and
bump in the CPI context. This is done by passing the seeds and bump to the
`with_signer` method when creating the CPI context.

```rust title="snippet"
pub fn mint_tokens(ctx: Context<MintTokens>, amount: u64) -> Result<()> {
    // [!code word:signer_seeds]
    // [!code highlight]
    let signer_seeds: &[&[&[u8]]] = &[&[b"mint", &[ctx.bumps.mint]]];

    let cpi_accounts = MintTo {
        mint: ctx.accounts.mint.to_account_info(),
        to: ctx.accounts.token_account.to_account_info(),
        authority: ctx.accounts.mint.to_account_info(),
    };
    let cpi_program = ctx.accounts.token_program.to_account_info();
    // [!code highlight:2]
    let cpi_context = CpiContext::new(cpi_program, cpi_accounts).with_signer(signer_seeds);
    token_interface::mint_to(cpi_context, amount)?;
    Ok(())
}
```

<Callout type="info">
  Note in this example the same PDA is used as both the address of the mint
  account and the mint authority.
</Callout>
